#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os,sys
import base64
import re
import httplib, urllib, urllib2
import traceback
import wx
import wx.xrc
import wx.richtext
from encodings import gbk 
from xml.dom import minidom
from datetime import datetime

FanfouID = ""
FanfouPassword = ""
FirstRunFlag = True
RefreshTime = 60000
Count = 20
dateReg = re.compile(r"\+\d{4}\s")
tellReg = re.compile(r"^(\s*<.*>)(.*)(</a>)$")
defaultTimeFormat = "%Y-%m-%d %H:%M:%S"
FanfouAPIAddress="api.Fanfou.com"
SendAPI="/statuses/update.xml"
MyAPI="/statuses/user_timeline.xml?count=%d"
FriendsAPI="/statuses/Friends_timeline.xml?count=%d"
PublicAPI="/statuses/public_timeline.xml?count=%d"
ReplieAPI="/statuses/replies.xml?count=%d"
PriMsgAPI="/direct_messages.xml?count=%d"
SendMsgAPI="/direct_messages/sent.xml?count=%d"
XRCFile = "wxFanfouResource.xrc"

def FanfouPost(url, headers, params):
    conn = httplib.HTTPConnection(FanfouAPIAddress)
    conn.request("POST",SendAPI,params,headers)
    response = conn.getresponse()
    if response.status != 200:
        raise HttpError(response.status, response.reason)
    else:
        return response

def FanfouGet(url):
    handler = urllib2.HTTPPasswordMgrWithDefaultRealm()
    handler.add_password(None, "http://" + FanfouAPIAddress, FanfouID, FanfouPassword)
    auth = urllib2.HTTPBasicAuthHandler(handler)
    opener = urllib2.build_opener(auth)
    response = opener.open("http://" + FanfouAPIAddress + url)
    return response

def parseTextNode(nodeList):
    result = ""
    for node in nodeList:
        if node.nodeType == node.TEXT_NODE:
            result = result + node.data
    return result

def parseStatus(statusNode):
    createdTime = parseTextNode(statusNode.getElementsByTagName("created_at")[0].childNodes)
    realTime = datetime.strptime(dateReg.sub("",createdTime),"%a %b %d %H:%M:%S %Y")
    text = parseTextNode(statusNode.getElementsByTagName("text")[0].childNodes)
    name = parseTextNode(statusNode.getElementsByTagName("screen_name")[0].childNodes)
    source = parseTextNode(statusNode.getElementsByTagName("source")[0].childNodes)
    return Status(name, text, realTime, source)

def parsePrivate(statusNode):
    createdTime = parseTextNode(statusNode.getElementsByTagName("created_at")[0].childNodes)
    realTime = datetime.strptime(dateReg.sub("",createdTime),"%a %b %d %H:%M:%S %Y")
    text = parseTextNode(statusNode.getElementsByTagName("text")[0].childNodes)
    name = parseTextNode(statusNode.getElementsByTagName("screen_name")[0].childNodes)
    source = ""
    return Status(name, text, realTime, source)

class Error(Exception):
    pass

class HttpError(Error):
    def __init__(self, code, reason):
        self.errorCode = code
        self.errorReason = reason

    def str(self):
        return "Http Communication Error(status:%d, reason:%s)" % (self.errorCode, self.errorReason)

class Status:
    def __init__(self, name, text, createdTime, source):
        self.text = text
        self.createdTime = createdTime
        self.name = name
        self.source = sourceCheck(source)
        
    def msgList(self):
        return (self.name, self.text, datetime.strftime(self.createdTime, defaultTimeFormat), self.source)

class FanfouClient:
    def __init__(self,username,password):
        self.username = username
        self.password = password
        self.authStr = base64.b64encode(username + ":" + password)

    def parseFanfouStatue(self,reader):
        xmldoc = minidom.parseString(reader.read())      
        nodes = xmldoc.getElementsByTagName("status")
        list = [parseStatus(node) for node in nodes]
        return list
    
    def parseFanfouPrivate(self,reader):
        xmldoc = minidom.parseString(reader.read())
        nodes = xmldoc.getElementsByTagName("direct_message")
        list = [parsePrivate(node) for node in nodes]
        return list
    
    def sendMessage(self,message):
        headers = {"Content-type": "application/x-www-form-urlencoded",
                "Accept": "text/xml",
                "Authorization": "Basic " + self.authStr}
        params = urllib.urlencode({"status": message, "source": "wxfanfou"})
        FanfouPost(SendAPI, headers, params)        

    def getMyMessages(self):
        response = FanfouGet(MyAPI %(Count))
        return self.parseFanfouStatue(response)

    def getFriendsMessages(self):
        response = FanfouGet(FriendsAPI %(Count))
        return self.parseFanfouStatue(response)

    def getPublicMessages(self):
        response = FanfouGet(PublicAPI % (Count))
        return self.parseFanfouStatue(response)
    
    def getReplieMessages(self):
        response = FanfouGet(ReplieAPI % (Count))
        return self.parseFanfouStatue(response)
    
    def getPrivateMessages(self):
        response = FanfouGet(PriMsgAPI % (Count))
        return self.parseFanfouPrivate(response)
    
    def getPriSendMessages(self):
        response = FanfouGet(SendMsgAPI % (Count))
        return self.parseFanfouPrivate(response)
    
def sourceCheck(source):
    result = tellReg.match(source)
    if result:
        return result.groups()[1]
    else:
        return source  

def textOutputFormat(msgs, textHead):
    msgsText = []
    msgsText.append(textHead)
    for eachMsg in msgs:
        listMsg = list(eachMsg.msgList())
        listTemp = list()
        for listLoop in range(4):
            listTemp.append(listMsg[listLoop])
        msgsText.append(listTemp)
    return msgsText 

def testSendMessage(client, msg):
    client.sendMessage(msg)

def testMyMessage(client):
    msgs = client.getMyMessages()
    return textOutputFormat(msgs, u"我的消息:")

def testFriendsMessage(cilent):
    msgs = client.getFriendsMessages()
    return textOutputFormat(msgs, u"大家的消息:")
    
def testPublicMessage(cilent):
    msgs = client.getPublicMessages()
    return textOutputFormat(msgs, u"随便看看:")

def testReplieMessage(cilent):
    msgs = client.getReplieMessages()
    return textOutputFormat(msgs, u"回复的消息:")

def testPrivateMessage(cilent):
    msgs = client.getPrivateMessages()
    return textOutputFormat(msgs, u"收到的私信:")

def testPriSendMessage(cilent):
    msgs = client.getPriSendMessages()
    return textOutputFormat(msgs, u"发出的私信:")

class LoginDialog(wx.App):
    infoInputed = False
    
    def OnInit(self):
        self.res = wx.xrc.XmlResource(XRCFile)
        self.frameLogin = self.res.LoadFrame(None, "frameLogin")
        self.panelLogin = wx.xrc.XRCCTRL(self.frameLogin, "panelLogin")
        self.textID = wx.xrc.XRCCTRL(self.frameLogin, "textID")
        self.textPassword = wx.xrc.XRCCTRL(self.frameLogin, "textPassword")
        self.buttonLogin = wx.xrc.XRCCTRL(self.frameLogin, "buttonLogin")
        self.Bind(wx.EVT_BUTTON, self.OnLoginButton, self.buttonLogin)
        self.frameLogin.Show()
        return True
    
    def OnLoginButton(self, event):
        global FanfouID
        global FanfouPassword
        FanfouID = self.textID.GetValue()
        FanfouPassword = self.textPassword.GetValue()
        if FanfouID and FanfouPassword:
            self.infoInputed = True
            self.frameLogin.Destroy()
        
    def getLoginStatus(self):
        return self.infoInputed
    
    def getFanfou(self):
        return FanfouID,FanfouPassword
    
class MainFrame(wx.App):
    def OnInit(self):
        self.res = wx.xrc.XmlResource(XRCFile)
        self.frameMain = self.res.LoadFrame(None, "frameMain")
        self.panelMain = wx.xrc.XRCCTRL(self.frameMain, "panelMain")
        self.richTextMessage = wx.richtext.RichTextCtrl(self.panelMain, style = wx.VSCROLL | wx.TE_AUTO_URL| wx.TE_READONLY | wx.TE_WORDWRAP, pos = (1,1), size=(298,358))
        self.textSend = wx.xrc.XRCCTRL(self.panelMain,"textSend")
        self.buttonSend = wx.xrc.XRCCTRL(self.panelMain, "buttonSend")
        self.buttonRefresh = wx.xrc.XRCCTRL(self.panelMain, "buttonRefresh")
        self.barMenu = self.res.LoadMenuBar("barMenu") 
        self.frameMain.SetMenuBar(self.barMenu)
        self.itemQuit = self.barMenu.FindItemById(wx.xrc.XRCID('itemQuit'))
        self.itemGetMyMessage = self.barMenu.FindItemById(wx.xrc.XRCID('itemGetMyMessage'))
        self.itemGetFriendsMessage = self.barMenu.FindItemById(wx.xrc.XRCID('itemGetFriendsMessage'))
        self.itemGetPublicMessage = self.barMenu.FindItemById(wx.xrc.XRCID('itemGetPubilcMessage'))
        self.itemGetReplieMessage = self.barMenu.FindItemById(wx.xrc.XRCID('itemGetReplieMessage'))
        self.itemGetPrivateMessage = self.barMenu.FindItemById(wx.xrc.XRCID('itemGetPrivateMessage'))
        self.itemGetPrivateMessage = self.barMenu.FindItemById(wx.xrc.XRCID('itemGetPostPrivateMessage'))
        self.itemAbout = self.barMenu.FindItemById(wx.xrc.XRCID('itemAbout '))
        self.timerMessageRefresh = wx.Timer(owner=None)
        self.timerMessageRefresh.Start(milliseconds = RefreshTime, oneShot = False )
        self.iconMain = wx.EmptyIcon()   
        self.iconMain.LoadFile("wxFanfou.ico",wx.BITMAP_TYPE_ICO)   
        self.frameMain.SetIcon(self.iconMain)
        self.Bind(wx.EVT_MENU, self.OnQuit, id = wx.xrc.XRCID("itemQuit"))
        self.Bind(wx.EVT_MENU, self.OnGetMyMsg, id = wx.xrc.XRCID("itemGetMyMessage"))
        self.Bind(wx.EVT_MENU, self.OnGetFriendsMsg, id = wx.xrc.XRCID("itemGetFriendsMessage"))
        self.Bind(wx.EVT_MENU, self.OnGetPublicMsg, id = wx.xrc.XRCID("itemGetPublicMessage"))
        self.Bind(wx.EVT_MENU, self.OnGetReplieMsg, id = wx.xrc.XRCID("itemGetReplieMessage"))
        self.Bind(wx.EVT_MENU, self.OnGetPrivateMsg, id = wx.xrc.XRCID("itemGetPrivateMessage"))
        self.Bind(wx.EVT_MENU, self.OnGetSendMsg, id = wx.xrc.XRCID("itemGetPostPrivateMessage"))
        self.Bind(wx.EVT_MENU, self.OnAbout, id = wx.xrc.XRCID ("itemAbout"))
        self.Bind(wx.EVT_BUTTON, self.OnSendButton ,self.buttonSend)
        self.Bind(wx.EVT_BUTTON, self.OnRefreshButton ,self.buttonRefresh)
        self.Bind(wx.EVT_TEXT_ENTER, self.OnSendButton ,self.textSend)
        self.Bind(wx.EVT_TIMER, self.OnTimerEvent, self.timerMessageRefresh)
        self.frameMain.Show()
        if FirstRunFlag == True:
            msgList = testFriendsMessage(client)
            self.msgRichTextOutput(msgList)
            self.msgDisplayStatus = "FriendsMessage"
            flagRunFlag = False
        return True
    
    def OnQuit(self, event):
        self.frameMain.Destroy()
   
    def OnGetMyMsg(self, event):
        self.msgDisplayStatus = "MyMessage"
        msgList = testMyMessage(client)
        self.msgRichTextOutput(msgList)
        
    def OnGetFriendsMsg(self, event):
        self.msgDisplayStatus = "FriendsMessage"
        msgList = testFriendsMessage(client)
        self.msgRichTextOutput(msgList)
        
    def OnGetPublicMsg(self, event):
        self.msgDisplayStatus = "PublicMessage"
        msgList = testPublicMessage(client)
        self.msgRichTextOutput(msgList)
    
    def OnGetPrivateMsg(self, event):
        self.msgDisplayStatus = "PrivateMessage"
        msgList = testPrivateMessage(client)
        self.msgRichTextOutput(msgList)    
    
    def OnGetReplieMsg(self, event):
        self.msgDisplayStatus = "ReplieMessage"
        msgList = testReplieMessage(client)
        self.msgRichTextOutput(msgList)
    
    def OnGetSendMsg(self, event):
        self.msgDisplayStatus = "SendMessage"
        msgList = testPriSendMessage(client)
        self.msgRichTextOutput(msgList)
    
    def OnSendButton(self, event):
        msg = self.textSend.GetValue()
        if msg != "":
            msg = msg.encode("gbk")
            testSendMessage(client, msg)
            self.msgDisplayStatus = "MyMessage"
            self.textSend.SetValue("")
            msgList = testMyMessage(client)
            self.msgRichTextOutput(msgList)
    
    def OnRefreshButton(self, event):
        if self.msgDisplayStatus == "MyMessage":
            msgList = testMyMessage(client)
            self.msgRichTextOutput(msgList)
        if self.msgDisplayStatus == "FriendsMessage":
            msgList = testFriendsMessage(client)
            self.msgRichTextOutput(msgList)
        if self.msgDisplayStatus == "PublicMessage":
            msgList = testPublicMessage(client)
            self.msgRichTextOutput(msgList)
        if self.msgDisplayStatus == "ReplieMessage":
            msgList = testReplieMessage(client)
            self.msgRichTextOutput(msgList)
        if self.msgDisplayStatus == "PrivateMessage":
            msgList = testPrivateMessage(client)
            self.msgRichTextOutput(msgList)
        
    
    def OnAbout(self, event):
        self.res = wx.xrc.XmlResource(XRCFile)
        self.dialogAbout = self.res.LoadDialog(None, "dialogAbout")
        self.panelAbout = wx.xrc.XRCCTRL(self.dialogAbout, "panelAbout")
        self.buttonAbout = wx.xrc.XRCCTRL(self.panelAbout, "buttonAbout")
        self.Bind(wx.EVT_BUTTON, self.OnAboutButton ,self.buttonAbout)
        self.dialogAbout.Show()
        return True
    
    def OnAboutButton(self, event):
        self.dialogAbout.Destroy()
        
    def OnTimerEvent(self, event):
        if self.msgDisplayStatus == "FriendsMessage":
            msgList = testFriendsMessage(client)
            self.msgRichTextOutput(msgList)
        elif self.msgDisplayStatus == "PublicMessage":
            msgList = testPublicMessage(client)
            self.msgRichTextOutput(msgList)
        elif self.msgDisplayStatus == "ReplieMessage":
            msgList = testReplieMessage(client)
            self.msgRichTextOutput(msgList)
        elif self.msgDisplayStatus == "PrivateMessage":
            msgList = testPrivateMessage(client)
            self.msgRichTextOutput(msgList)
        
    def msgRichTextOutput(self,msgList):
            self.richTextMessage.Clear()
            wx.CallAfter(self.richTextMessage.SetFocus)
            self.richTextMessage.BeginTextColour((0, 0 ,0))
            self.richTextMessage.BeginFontSize(12)
            self.richTextMessage.WriteText(msgList[0])
            self.richTextMessage.EndFontSize()
            self.richTextMessage.EndTextColour()
            
            for listLoop in range(1,Count + 1):
                self.richTextMessage.Newline()
                self.richTextMessage.BeginTextColour((0, 0, 0))
                self.richTextMessage.BeginFontSize(10)
                self.richTextMessage.WriteText(msgList[listLoop][0] + ":")
                
                self.richTextMessage.EndTextColour()
                self.richTextMessage.EndFontSize()
                self.richTextMessage.BeginTextColour((0, 171, 255))
                self.richTextMessage.BeginFontSize(9)
                self.richTextMessage.WriteText(msgList[listLoop][1])
                self.richTextMessage.EndTextColour()
                self.richTextMessage.EndFontSize()
                self.richTextMessage.Newline()
                
                self.richTextMessage.BeginTextColour((200, 20, 20))
                self.richTextMessage.BeginFontSize(8)
                if msgList[listLoop][3] != "":
                    self.richTextMessage.WriteText(u"通过 ")
                    self.richTextMessage.WriteText(msgList[listLoop][3])
                    self.richTextMessage.WriteText(" ")
                self.richTextMessage.WriteText(u"在 " + msgList[listLoop][2] + u"发出")
                self.richTextMessage.EndFontSize()
                self.richTextMessage.EndTextColour()
                self.richTextMessage.Newline()
       
            
if __name__ == "__main__":
    LoginDialog = LoginDialog(redirect = False)
    LoginDialog.MainLoop()
    if LoginDialog.getLoginStatus() == True:
        FanfouID, FanfouPassword = LoginDialog.getFanfou()
        client = FanfouClient(FanfouID, FanfouPassword)
        MainFrame = MainFrame(redirect = False)
        MainFrame.MainLoop()